package ysq.weixin.client;

import com.alibaba.fastjson.JSON;
import it.sauronsoftware.jave.AudioAttributes;
import it.sauronsoftware.jave.Encoder;
import it.sauronsoftware.jave.EncodingAttributes;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
import org.apache.commons.collections.map.HashedMap;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import ysq.weixin.model.EwmMessage;
import ysq.weixin.model.PayEntity;
import ysq.weixin.model.Return_pay;
import ysq.weixin.model.TemplateMessage;
import ysq.weixin.model.info.*;
import ysq.weixin.util.WxUrlUtil;
import ysq.weixin.util.httpclient.HttpUtil;
import ysq.xyg.util.BaseUtil;
import ysq.xyg.util.DateUtil;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.util.Date;
import java.util.Formatter;
import java.util.Map;
import java.util.logging.Logger;

/**
 * Created by bingcai(bingly@foxmail.com) on 2017/6/22 0022.
 */
public class WxApi {

    private static Logger log= Logger.getLogger(WxApi.class.getName());

    //获取接口访问凭证
    public static AccessToken getAccessToken(String appId, String appSecret) {
        AccessToken token = null;
        String tockenUrl = WxUrlUtil.getTokenUrl(appId, appSecret);
        JSONObject jsonObject = HttpUtil.httpRequestAndReturnResult(tockenUrl, HttpMethod.GET, null);
        if (null != jsonObject && !jsonObject.containsKey("errcode")) {
            try {
                token = new AccessToken();
                token.setExpiresIn(jsonObject.getInt("expires_in"));
                token.setEndTime(DateUtil.getSecondOneDate(new Date(),token.getExpiresIn()-180));//提前3分钟结束
                token.setAccessToken(jsonObject.getString("access_token"));
            } catch (JSONException e) {
                token = null;//获取token失败
            }
        }else if(null != jsonObject){
            token = new AccessToken();
            token.setErrcode(jsonObject.getInt("errcode"));
        }
        return token;
    }
    //获取OAuth2.0 Token
    public static OAuthAccessToken getOAuthAccessToken(String appId, String appSecret, String code) {
        OAuthAccessToken token = null;
        String tockenUrl = WxUrlUtil.getOAuthTokenUrl(appId, appSecret, code);
        JSONObject jsonObject = HttpUtil.httpRequestAndReturnResult(tockenUrl, HttpMethod.GET, null);
        if (null != jsonObject && !jsonObject.containsKey("errcode")) {
            try {
                token = new OAuthAccessToken();
                token.setOauthAccessToken(jsonObject.getString("access_token"));
                token.setExpiresIn(jsonObject.getInt("expires_in"));
                token.setOpenid(jsonObject.getString("openid"));
                token.setScope(jsonObject.getString("scope"));
            } catch (JSONException e) {
                token = null;//获取token失败
            }
        }else if(null != jsonObject){
            token = new OAuthAccessToken();
            token.setErrcode(jsonObject.getInt("errcode"));
        }
        return token;
    }
    //获取OAuth2.0 UserInfo
    public static User getOAuthUserInfo(OAuthAccessToken oAuthAccessToken) {
        User user = null;
        String oAuthUserinfoUrl = WxUrlUtil.getOAuthUserinfoUrl(oAuthAccessToken.getOauthAccessToken(),oAuthAccessToken.getOpenid());
        JSONObject jsonObject = HttpUtil.httpRequestAndReturnResult(oAuthUserinfoUrl, HttpMethod.GET, null);
        if (null != jsonObject && !jsonObject.containsKey("errcode")) {
            try {
                user = new User();
                user.setOpenid(jsonObject.getString("openid"));
                user.setNickname(jsonObject.getString("nickname"));
                user.setHeadlogo(jsonObject.getString("headimgurl"));
                if (jsonObject.containsKey("unionid")) {
                    String unionid=jsonObject.getString("unionid");
                    if(unionid!=null&&unionid!="") {
                        user.setUnionid(jsonObject.getString("unionid"));
                    }
                }
            } catch (JSONException e) {
                user = null;//获取token失败
            }
        }
        return user;
    }

    /**
     * 小程序获取用户信息
     * */
    protected static Map<String,Object> xcxAcceptUserInfo(String appId, String appSecret, String code){
        Map<String,Object> map=new HashedMap();
        String xcxUserInfoUrl = WxUrlUtil.getXcxUserInfoUrl(appId,appSecret,code);
        JSONObject jsonObject = HttpUtil.httpRequestAndReturnResult(xcxUserInfoUrl, HttpMethod.GET, null);
        if (null != jsonObject && !(jsonObject.containsKey("errcode"))) {
            map.put("errcode",0);
            map.put("openid",jsonObject.getString("openid"));
            map.put("sessionKey",jsonObject.getString("session_key"));
            if( jsonObject.containsKey("unionid")){
                map.put("unionid",jsonObject.getString("unionid"));
            }else{
                map.put("unionid","");
            }
        }else if(null != jsonObject){
            map.put("errcode",jsonObject.getInt("errcode"));
            map.put("errmsg",jsonObject.getString("errmsg"));
        }
        return map;
    }
    /**
     * 小程序二维码图片信息
     * */
    protected static  Map<String,Object> xcxAcceptEwm(String access_token, String directory, String fileName, EwmMessage ewmMessage, boolean isCover){
        Map<String,Object> map=new HashedMap();
        File dirFile = new File(directory);
        File file = new File(directory,fileName);
        map.put("errcode",0);
        map.put("path",file.getAbsolutePath());
        if (!dirFile.isDirectory()) {
            // 如果目录不存在，则创建目录
            dirFile.mkdirs();
        }
        if (file.exists()&&(!isCover)){
            //当图片存在直接返回
        }else{
            String e= JSON.toJSONString(ewmMessage);
            String xcxUserInfoUrl = WxUrlUtil.getXcxEwmUrl(access_token);
            byte[] result = HttpUtil.httpsRequestByte(xcxUserInfoUrl, HttpMethod.POST, e);
            InputStream inputStream = null;
            OutputStream outputStream = null;
            inputStream = new ByteArrayInputStream(result);
            long num=result.length;
            try {
                if(num<200){
                    byte[] bytes = new byte[0];
                    bytes = new byte[inputStream.available()];
                    inputStream.read(bytes);
                    String str = new String(bytes);
                    map.put("errcode",1);
                    map.put("errmsg",str);
                }else{
                    if (!file.exists()){
                        file.createNewFile();
                    }
                    outputStream = new FileOutputStream(file);
                    int len = 0;
                    byte[] buf = new byte[1024];
                    while ((len = inputStream.read(buf, 0, 1024)) != -1) {
                        outputStream.write(buf, 0, len);
                    }
                    outputStream.flush();
                    outputStream.close();
                    inputStream.close();
                }

            } catch (IOException e1) {
                map.put("errcode",1);
                map.put("errmsg",e1.toString());
            }
        }
        return map;
    }
    /**
     * 小程序二维码图片信息
     * */
    protected static  Map<String,Object> xcxAcceptEwmXz(String access_token, String directory, String fileName, EwmMessage ewmMessage, boolean isCover){
        Map<String,Object> map=new HashedMap();
        File dirFile = new File(directory);
        File file = new File(directory,fileName);
        map.put("errcode",0);
        map.put("path",file.getAbsolutePath());
        if (!dirFile.isDirectory()) {
            // 如果目录不存在，则创建目录
            dirFile.mkdirs();
        }
        if (file.exists()&&(!isCover)){
            //当图片存在直接返回
        }else{
            String e= JSON.toJSONString(ewmMessage);
            String xcxUserInfoUrl = WxUrlUtil.getXcxEwmXzUrl(access_token);
            byte[] result = HttpUtil.httpsRequestByte(xcxUserInfoUrl, HttpMethod.POST, e);
            InputStream inputStream = null;
            OutputStream outputStream = null;
            inputStream = new ByteArrayInputStream(result);
            try {
                if (!file.exists()){
                    file.createNewFile();
                }
                outputStream = new FileOutputStream(file);
                int len = 0;
                byte[] buf = new byte[1024];
                while ((len = inputStream.read(buf, 0, 1024)) != -1) {
                    outputStream.write(buf, 0, len);
                }
                outputStream.flush();
                outputStream.close();
                inputStream.close();
            } catch (IOException e1) {
                map.put("errcode",1);
                map.put("errmsg",e1.toString());
            }
        }
        return map;
    }
    //获取js ticket
    public static JSTicket getJSTicket(String token){
        JSTicket jsTicket = null;
        String jsTicketUrl = WxUrlUtil.getJsApiTicketUrl(token);
        JSONObject jsonObject = HttpUtil.httpRequestAndReturnResult(jsTicketUrl, HttpMethod.GET, null);
        if (null != jsonObject && jsonObject.containsKey("errcode") && jsonObject.getInt("errcode") == 0) {
            try {
                jsTicket = new JSTicket();
                jsTicket.setTicket(jsonObject.getString("ticket"));
                jsTicket.setExpiresIn(jsonObject.getInt("expires_in"));
            } catch (JSONException e) {
                jsTicket = null;//获取token失败
            }
        }else if(null != jsonObject){
            jsTicket = new JSTicket();
            jsTicket.setErrcode(jsonObject.getInt("errcode"));
        }
        return jsTicket;
    }
    /**
     * JSTicket 加密
     * */
    public static JSTicketShareResponse sign(String ticket, String url){
        String nonce_str = BaseUtil.uId();
        String timestamp = DateUtil.create_timestamp();
        String string1;
        String signature = "";

        //注意这里参数名必须全部小写，且必须有序
        string1 = "jsapi_ticket=" + ticket +
                "&noncestr=" + nonce_str +
                "&timestamp=" + timestamp +
                "&url=" + url;
        try{
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(string1.getBytes("UTF-8"));
            signature = byteToHex(crypt.digest());
        }catch (Exception e){
            e.printStackTrace();
        };
        return new JSTicketShareResponse(url,nonce_str,timestamp,signature);
    }

    /**
     * 从微信下载语音，并存储到硬盘
     * @Title: handleVoice
     * @Description: TODO(从微信下载语音，并存储到硬盘)
     * @author  pll
     * @param @param userid 用户ID
     * @param @param mediaId 从微信下载所需语音ID
     * @return void 返回类型
     * @throws
     */
    public static String handleVoice(String accesstoken,String mediaId,String realPath){
        //accesstoken
        InputStream inputStream = null;

        String url = "https://qyapi.weixin.qq.com/cgi-bin/media/get?access_token="+accesstoken+"&media_id=" + mediaId;

        // 自定义的文件amr
        String baseUrl=DateUtil.DateToStr(new Date(),DateUtil.DATE_TIME_PATTERN_1)+ BaseUtil.acceptRandom(BaseUtil.NUMBER_CONTENT,6);
        String  amrFileName = "/upload/"+baseUrl+".amr";
        String  mp3FileName = "/upload/"+baseUrl+".mp3";

        try {
            URL urlGet = new URL(url);
            HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
            http.setRequestMethod("GET"); // 必须是get方式请求
            http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
            http.setDoOutput(true);
            http.setDoInput(true);
            System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 连接超时30秒
            System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 读取超时30秒
            http.connect();
            // 获取文件转化为byte流
            inputStream = http.getInputStream();
            byte[] data = new byte[10240];
            int len = 0;
            FileOutputStream fileOutputStream = null;

            try {
                fileOutputStream = new FileOutputStream(realPath+amrFileName);
                while ((len = inputStream.read(data)) != -1) {
                    fileOutputStream.write(data, 0, len);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (fileOutputStream != null) {
                    try {
                        fileOutputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }


        } catch (Exception e) {
            e.printStackTrace();
        }
        changeToMp3(realPath+amrFileName,realPath+mp3FileName);
        return mp3FileName;
    }

    public static void changeToMp3(String sourcePath, String targetPath) {
        File source = new File(sourcePath);
        File target = new File(targetPath);
        AudioAttributes audio = new AudioAttributes();
        Encoder encoder = new Encoder();

        audio.setCodec("libmp3lame");
        EncodingAttributes attrs = new EncodingAttributes();
        attrs.setFormat("mp3");
        attrs.setAudioAttributes(audio);

        try {
            encoder.encode(source, target, attrs);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 发送模板消息
     * @return
     */
    public static JSONObject sendTemplateMessage(TemplateMessage tplMsg, String accessToken){
        if(tplMsg != null){
            return HttpUtil.httpRequestAndReturnResult(WxUrlUtil.getSendTemplateMessageUrl(accessToken), HttpMethod.POST, tplMsg.toString());
        }
        return null;
    }

    /**
     * 微信支付-统一订单
     * */
    public static Return_pay pay_unifiedorder(PayEntity payEntity,String key){
        log.info("==================统一标签============================");
        //获取签名
        String signString=payEntity.getResultSign(key);
        payEntity.setSign(signString);
        log.info("sign:"+signString);
        //获取XML
        String params=payEntity.getXML();
        log.info("params XML:"+params);
        //获取微信返回值XML
        String xml=HttpUtil.httpXml(WxUrlUtil.getPayNoticeUrl(), params);
        log.info("XML:"+xml);
        Return_pay pay=new Return_pay();
        Document document=null;
        try{
            document = DocumentHelper.parseText(xml);
        }catch(Exception e){
            e.toString();
        }
        Element root=document.getRootElement();
        String return_code = root.elementText("return_code");
        log.info("return_code:"+return_code);
        pay.setReturn_code(return_code);
        if("SUCCESS".equalsIgnoreCase(return_code)){
            String appid = root.elementText("appid");
            pay.setAppid(appid);
            log.info("appid:"+appid);

            String mch_id = root.elementText("mch_id");
            pay.setMch_id(mch_id);
            log.info("mch_id:"+mch_id);

            String nonce_str = root.elementText("nonce_str");
            pay.setNonce_str(nonce_str);
            log.info("nonce_str:"+nonce_str);

            String device_info = root.elementText("device_info");
            pay.setDevice_info(device_info);
            log.info("device_info:"+device_info);

            String sign = root.elementText("sign");
            pay.setSign(sign);
            log.info("sign:"+sign);

            String result_code = root.elementText("result_code");
            pay.setResult_code(result_code);
            log.info("result_code:"+result_code);

            if("SUCCESS".equalsIgnoreCase(result_code)){
                String trade_type = root.elementText("trade_type");
                pay.setTrade_type(trade_type);
                log.info("trade_type:"+trade_type);

                String prepay_id = root.elementText("prepay_id");
                pay.setPrepay_id(prepay_id);
                log.info("prepay_id:"+prepay_id);

                if("NATIVE".equalsIgnoreCase(trade_type)){
                    String code_url  = root.elementText("code_url");
                    pay.setCode_url(code_url);
                    log.info("code_url:"+code_url);
                }
            }else{
                String err_code = root.elementText("err_code");
                pay.setErr_code(err_code);
                log.info("err_code:"+err_code);

                String err_code_des = root.elementText("err_code_des");
                pay.setErr_code_des(err_code_des);
                log.info("err_code_des:"+err_code_des);
            }
        }else{
            String return_msg = root.elementText("return_msg");
            pay.setReturn_msg(return_msg);
            log.info("return_msg:"+return_msg);
        }
        log.info("pay.toString():"+pay.toString());
        return pay;
    }

    private static String byteToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash)
        {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

}
